home *** CD-ROM | disk | FTP | other *** search
/ Symantec Visual Cafe for Java 2.5 / symantec-visual-cafe-2.5-database-dev-edition.iso / Visual Cafe Pro v1.0 / SOURCE.BIN / DbaDataStore.java < prev    next >
Encoding:
Java Source  |  1997-06-19  |  22.0 KB  |  788 lines

  1. /*
  2.  * DbaDataStore.java   1.0   12 Jan 1997
  3.  *
  4.  * Copyright (c) 1996 Krumel & Associates, Inc.  All Rights Reserved.
  5.  *
  6.  * This software is provided as is.  Krumel & Associates shall not be liable
  7.  * for any damages suffered by licensee as a result of using, modifying or
  8.  * distributing this software or its derivatives.
  9.  */
  10.  
  11. package symantec.itools.db.awt;
  12.  
  13. import symantec.itools.db.pro.*;
  14. import symjava.sql.SQLException;
  15. import java.util.BitSet;
  16. import symjava.sql.Types;
  17.  
  18. //All rows coming from DbDataSource are 0 relative
  19. //All cols coming from DbDataSource are 1 relative
  20. public class DbaDataStore  implements DbDataStore, MetaTable, DbDataUpdater {
  21.     Position        position;
  22.     RelationView    master;
  23.     RelationView    relView;
  24.     MultiView       multiView;
  25.     DbDataSource    source = null;
  26.     DbaDataLink     link;
  27.     int             coltoshow=0;
  28.     RelationViewMetaData    meta;
  29.  
  30.     public static final int MAX_DISPLAY_SIZE = 60;
  31.  
  32.     public DbaDataStore(RelationView rv, RelationView masterView) throws SQLException {
  33.         if (masterView != null)
  34.         {
  35.             master = masterView;
  36.         }
  37.         relView = rv;
  38.         multiView = rv.getMultiView();
  39.         meta = relView.getMetaData();
  40.         position = new Position(rv);
  41.     }
  42.  
  43.     void resetRows() throws SQLException
  44.     {
  45.         int count;
  46.         // // synchronized(position)
  47.         {
  48.             count = position.getIgnoreCount();
  49.         }
  50.         if (count > 0)
  51.         {
  52.             return;
  53.         }
  54.         initRowMapping();
  55.         source.view.clear();
  56.         // source.view.redrawAsync();   // clear calls redrawAsync
  57.     }
  58.  
  59.     void notifyRecordChange() throws SQLException
  60.     {
  61.         int count;
  62.         // synchronized(position)
  63.         {
  64.             count = position.getIgnoreCount();
  65.         }
  66.         if (count > 0)
  67.         {
  68.             return;
  69.         }
  70.         int row;
  71.         // synchronized(position)
  72.         {
  73.             row = position.get();
  74.         }
  75.  
  76.         if (relView.getCurrentRecordState() == Record.RECSTATE_NEW)
  77.         {
  78.             source.view.scrollUpDownAbsolute(row -1);
  79.         }
  80.  
  81.         source.view.setFocusToRow(row);
  82.     }
  83.  
  84.     public void fetchMode(boolean manual)
  85.     {
  86.         setManRowChangeFlag(manual);
  87.     }
  88.  
  89.     public boolean manualRowChangeFlag()
  90.     {
  91.         // synchronized (position)
  92.         {
  93.             return position.getNotificationMode();
  94.         }
  95.     }
  96.  
  97.     private void setManRowChangeFlag(boolean val)
  98.     {
  99.         try
  100.         {
  101.             // synchronized (position)
  102.             {
  103.                 position.setNotificationMode(val);
  104.             }
  105.         }
  106.         catch(SQLException ex) {}
  107.     }
  108.  
  109.     public void setCurrentRow(int row) throws TypeNotSupported {
  110.         row++;
  111.         try
  112.         {
  113.             int translatedRow = translateRow(row);
  114.             // synchronized (position)
  115.             {
  116.                 position.set(translatedRow);
  117.             }
  118.         } catch(Exception ex)
  119.         {
  120.             throw new TypeNotSupported(ex.getMessage());
  121.         }
  122.     }
  123.  
  124.     public boolean isCurrentRow(int row) {
  125.         try
  126.         {
  127.             int translatedRow = translateRow(row);
  128.             // synchronized (position)
  129.             {
  130.                 return translatedRow == position.get();
  131.             }
  132.         }
  133.         catch(Exception ex)
  134.         {
  135.             return false;
  136.         }
  137.     }
  138.  
  139.     public void setDbDataSource(DbDataSource ds) {
  140.         if (source != null)
  141.         {
  142.             return;
  143.         }
  144.         source = ds;
  145.         initRowMapping();
  146.         link = new DbaDataLink(this);
  147.         // synchronized(position)
  148.         {
  149.             position.ignoreNotification(true);
  150.         }
  151.         try
  152.         {
  153.             relView.bindRecordSet(link);
  154.             relView.bindCurrentRecord(link);
  155.         } catch(SQLException ex) { /*this should never happend*/ }
  156.         // synchronized(position)
  157.         {
  158.             position.ignoreNotification(false);
  159.         }
  160.     }
  161.  
  162.     public boolean supportsCaching() {
  163.         return true;
  164.     }
  165.  
  166.     public int validDataRowRange(int top, int bottom) throws DataNotAvailable {
  167.         //iterate from top to bottom and find the last valid number in range
  168.  
  169.         //adjust for row indices being zero relative
  170.  
  171.         top++;
  172.         bottom += 2;  //a few extra for scrollbars
  173.  
  174.         int lastInRange = Math.max(1, top); //always want to ensure at least try
  175.                                             //first row
  176.  
  177.         try {
  178.             setManRowChangeFlag(true);
  179.             while(lastInRange<=bottom) {
  180.                 translateRow(lastInRange);
  181.                 lastInRange++;
  182.             }
  183.         } catch(DataNotAvailable ex) {
  184.         } finally {
  185.             setManRowChangeFlag(false);
  186.         }
  187.  
  188.         if (lastInRange == top) {
  189.             throw new DataNotAvailable("top is greater than last row in database");
  190.         }
  191.  
  192.         return lastInRange-1;
  193.     }
  194.  
  195.     public Data getData(int row, int col) throws DataNotAvailable {
  196.         //adjust for row indices being 0 relative
  197.         row++;
  198.         Data d = null;
  199.  
  200.         try {
  201.             setManRowChangeFlag(true);
  202.             int translatedRow = translateRow(row);
  203.             boolean success;
  204.             // synchronized(position)
  205.             {
  206.                 success = position.set(translatedRow);
  207.             }
  208.             if (!success) {
  209.                 throw new DataNotAvailable("Could not move to row " + row);
  210.             }
  211.  
  212.             String str = relView.getStringValue(col);
  213.             if (str == null) { str = ""; }
  214.             d = new ImageStringData(source, str);
  215.         } catch(Exception ex) {
  216.             throw new DataNotAvailable(ex.getMessage());
  217.         } finally {
  218.             setManRowChangeFlag(false);
  219.         }
  220.  
  221.         return d;
  222.     }
  223.  
  224.  
  225.     public void update(int row, int col, Data data) throws TypeNotSupported {
  226.         //adjust for row indices being 0 relative
  227.         row++;
  228.         try {
  229.             setManRowChangeFlag(true);
  230.             int translatedRow = translateRow(row);
  231.             // synchronized(position)
  232.             {
  233.                 position.set(translatedRow);
  234.                 // position.ignoreNotification(true);
  235.             }
  236.             //assume only string support for now
  237.             relView.setValueFromString(col, data.toString());
  238.             // synchronized(position)
  239.             {
  240.                 // position.ignoreNotification(false);
  241.             }
  242.         } catch(Exception ex) {
  243.             throw new TypeNotSupported(ex.getMessage());
  244.         } finally {
  245.             setManRowChangeFlag(false);
  246.         }
  247.     }
  248.  
  249.     public int rowState(int row)
  250.     {
  251.         //adjust for row indices being 0 relative
  252.         row++;
  253.  
  254.         int rowState = DataSource.NEW_ROW;
  255.         try
  256.         {
  257.             setManRowChangeFlag(true);
  258.             int translatedRow = translateRow(row);
  259.             // synchronized(position)
  260.             {
  261.                 position.set(translatedRow);
  262.             }
  263.             byte state = relView.getCurrentRecordState();
  264.             switch(state)
  265.             {
  266.                 case Record.RECSTATE_NEW:
  267.                     rowState = DataSource. NEW_ROW; break;
  268.                 case Record.RECSTATE_DELETED:
  269.                     rowState = DataSource. DELETED_ROW; break;
  270.                 case Record.RECSTATE_MODIFIED:
  271.                     rowState = DataSource. MODIFIED_ROW; break;
  272.                 case Record.RECSTATE_EXISTING:
  273.                     rowState = DataSource. CLEAN_ROW; break;
  274.                 default:
  275.                     //now what?!?
  276.             }
  277.         }
  278.         catch(Exception ex)
  279.         {
  280.             //if fails assume new
  281.             ex.printStackTrace();
  282.         }
  283.         finally
  284.         {
  285.             setManRowChangeFlag(false);
  286.         }
  287.  
  288.         return rowState;
  289.     }
  290.  
  291.     public void clear() {
  292.         initRowMapping();  //time to start all over
  293.     }
  294.  
  295.     public void refresh() {
  296.         try {
  297.             relView.restartMultiView();
  298.         } catch(SQLException ex) {
  299.         }
  300.     }
  301.  
  302.     public void undoRow(int row) throws TypeNotSupported {
  303.         row++;
  304.  
  305.         try {
  306.             // synchronized(position)
  307.             {
  308.                 position.ignoreNotification(true);
  309.             }
  310.             relView.undoRecord();
  311.         } catch(SQLException ex) {
  312.             throw new TypeNotSupported(ex.getMessage());
  313.         } finally {
  314.             // synchronized(position)
  315.             {
  316.                 position.ignoreNotification(false);
  317.             }
  318.         }
  319.     }
  320.  
  321.     public int rowsRetrieved() {
  322.         return lastIndex_;
  323.     }
  324.  
  325.     public int fetchAllRows() {
  326.         int count=1;
  327.  
  328.         try {
  329.             setManRowChangeFlag(true);
  330.             while(true) {
  331.                 translateRow(count);
  332.                 count++;
  333.             }
  334.         } catch(DataNotAvailable ex) {
  335.         } finally {
  336.             setManRowChangeFlag(false);
  337.         }
  338.  
  339.         return count-1;
  340.     }
  341.  
  342.  
  343.     //-------------------------------------------------------------------------
  344.     //              DbUpdater Methods
  345.     //-------------------------------------------------------------------------
  346.  
  347.     public void undeleteRow(int row) throws TypeNotSupported {
  348.         try {
  349.             row++;
  350.             // synchronized(position)
  351.             {
  352.                 position.ignoreNotification(true);
  353.             }
  354.             relView.undoRecord();
  355.         } catch(SQLException ex) {
  356.             throw new TypeNotSupported(ex.getMessage());
  357.         } finally {
  358.             // synchronized(position)
  359.             {
  360.                 position.ignoreNotification(false);
  361.             }
  362.         }
  363.     }
  364.  
  365.     public void deleteRow(int row) throws TypeNotSupported {
  366.         try {
  367.             //adjust for row indices being zero relative
  368.             row++;
  369.             // synchronized(position)
  370.             {
  371.                 position.ignoreNotification(true);
  372.             }
  373.             relView.deleteRecord();
  374.         } catch(SQLException ex) {
  375.             throw new TypeNotSupported(ex.getMessage());
  376.         } finally {
  377.             // synchronized(position)
  378.             {
  379.                 position.ignoreNotification(false);
  380.             }
  381.         }
  382.     }
  383.  
  384.     public void save() throws TypeNotSupported {
  385.         try {
  386.             relView.saveMultiView();
  387.         } catch(SQLException ex) {
  388.             throw new TypeNotSupported(ex.getMessage());
  389.         }
  390.     }
  391.  
  392.     public void getNewRecord() throws TypeNotSupported
  393.     {
  394.         try {
  395.             relView.getNewRecord();
  396.         } catch(SQLException ex) {
  397.             throw new TypeNotSupported(ex.getMessage());
  398.         }
  399.     }
  400.  
  401.     public void insertRow(int row) throws TypeNotSupported {
  402.         appendRow();
  403.     }
  404.  
  405.     public int appendRow() throws TypeNotSupported {
  406.         /*
  407.         // synchronized(position)
  408.         {
  409.             position.ignoreNotification(true);
  410.         }
  411.         */
  412.         getNewRecord();
  413.         /*
  414.         // synchronized(position)
  415.         {
  416.             position.ignoreNotification(true);
  417.         }
  418.         */
  419.         return 0;
  420.     }
  421.  
  422.     //-------------------------------------------------------------------------
  423.     //              MetaTable Methods
  424.     //-------------------------------------------------------------------------
  425.     public void setColtoShow(int val){
  426.         coltoshow=val;}
  427.         
  428.     public void setupGrid(Grid view) {
  429.         try {
  430.             
  431.             //create the proper number of columns
  432.             //make sure the BasicCell is set as default
  433.             view.setAutoRedraw(false);
  434.             //int cols = meta.getColumnCount();
  435.             int cols = coltoshow;
  436.             if(coltoshow==0||meta.getColumnCount()<=coltoshow)
  437.             cols=meta.getColumnCount();
  438.             view.createColumns(cols);
  439.  
  440.             //setup row headings
  441.             view.setRowLabelHeadingStyle(Grid.AUTONUMBER);
  442.  
  443.             //set the column headings and widths
  444.             for (int col=1; col<=cols; col++) {
  445.                 int size = meta.getColumnDisplaySize(col);
  446.                 size = Math.min(0, size);
  447.                 size = Math.max(0, MAX_DISPLAY_SIZE);
  448.                 view.setHeading(meta.getColumnLabel(col),
  449.                                 col,
  450.                                 java.lang.Math.min(size, 10));
  451.                 setupColumn(view, col);
  452.             }
  453.  
  454.             view.setAutoRedraw(true);
  455.         } catch(SQLException ex) {
  456.             //Not much to do here but set one heading called error
  457.             //and set the message in the first cell
  458.         }
  459.     }
  460.  
  461.     public void setDataSource(DataSource ds) { }
  462.  
  463.     public boolean isDataEditable(int row, int col) throws DataNotAvailable {
  464.         try {
  465.             //adjust for row indices being zero relative
  466.             row++;
  467.             setManRowChangeFlag(true);
  468.             int translatedRow = translateRow(row);
  469.             boolean success;
  470.             // synchronized(position)
  471.             {
  472.                 success = position.set(translatedRow);
  473.             }
  474.             if (success) {
  475.                 return meta.isWritable(col) && relView.isCurrentRecordWritable();
  476.             }
  477.         } catch(SQLException ex) {
  478.             throw new DataNotAvailable(ex.getMessage());
  479.         } finally {
  480.             setManRowChangeFlag(false);
  481.         }
  482.  
  483.         //this should never be reached
  484.         return true;
  485.     }
  486.  
  487.     public Data[] arrangeForViewing(Data data[]) {
  488.         return data;
  489.     }
  490.  
  491.     public void setupColumn(Grid view, int col) {
  492.         //assume all cols aligned left
  493.         try {
  494.             int type = meta.getColumnType(col);
  495.             switch(type) {
  496.                 case Types.BIGINT:
  497.                 case Types.INTEGER:
  498.                 case Types.DOUBLE:
  499.                 case Types.FLOAT:
  500.                 case Types.NUMERIC:
  501.                 case Types.SMALLINT:
  502.                 case Types.TINYINT:
  503.                 case Types.REAL:
  504.                     view.setColumnAlignment(col,Grid.RIGHT);
  505.                     break;
  506.                 case Types.CHAR:
  507.                 case Types.DATE:
  508.                 case Types.VARCHAR:
  509.                 case Types.LONGVARCHAR:
  510.                 case Types.NULL:
  511.                 case Types.OTHER:
  512.                 case Types.BINARY:
  513.                 case Types.VARBINARY:
  514.                 case Types.LONGVARBINARY:
  515.                 case Types.TIME:
  516.                 case Types.TIMESTAMP:
  517.                 case Types.BIT:
  518.                 default:
  519.                     view.setColumnAlignment(col,Grid.LEFT);
  520.             }
  521.  
  522.             if (meta.isCurrency(col)) {
  523.                 view.setColumnAlignment(col,Grid.RIGHT);
  524.             }
  525.  
  526.             if (!meta.isWritable(col)) {
  527.                 view.setColEditable(col, false);
  528.             }
  529.         } catch(SQLException ex) {
  530.             //why not try a default
  531.             view.setColumnAlignment(col,Grid.LEFT);
  532.         }
  533.     }
  534.  
  535.     //all map functions work on 1 relative rows!!!
  536.     int     rowMapping[];
  537.     BitSet  createdRows;
  538.     int     lastValidIndex;
  539.     int     lastIndex_ = 0;         //pointer to last element in map,
  540.                                     //waste the first
  541.     int     lastRowRetrieved = 0;   //last row retrieved using position.set()
  542.  
  543.     boolean obtainedAllRows = false;
  544.  
  545.     final static int START_SIZE = 100;
  546.     final static int INC_SIZE = 100;
  547.  
  548.     private void initRowMapping() {
  549.             rowMapping = new int[START_SIZE];
  550.             lastValidIndex = START_SIZE -1;
  551.             lastRowRetrieved = 0;
  552.             lastIndex_ = 0;
  553.             obtainedAllRows = false;
  554.             createdRows = new BitSet();
  555.     }
  556.  
  557.     void printMap() {
  558.         System.out.println("Row mappings - size="+lastValidIndex +
  559.                        "\n\tlastIndex="+lastIndex_+ "  lastRow="+lastRowRetrieved);
  560.         for(int i=0;i<=lastIndex_; i++) {
  561.             System.out.println("\trow "+i+" -> "+rowMapping[i]);
  562.         }
  563.     }
  564.  
  565.     private int translateRow(int r) throws DataNotAvailable {
  566.         boolean success;
  567.         try {
  568.             while(lastIndex_ < r) {
  569.                 //if lastRowRetrieved has already been obtained through
  570.                 //an insert then increment and keep going
  571.                 if (createdRows.get(lastRowRetrieved+1)) {
  572.                     lastRowRetrieved++;
  573.                     continue;
  574.                 }
  575.  
  576.                 //need to fetch rows up to 'r'
  577.  
  578.                 // synchronized(position)
  579.                 {
  580.                     success = position.set(lastRowRetrieved+1);
  581.                 }
  582.                 if (!success) {
  583.                     obtainedAllRows = true;   //set the flag and boogie out
  584.                     throw new DataNotAvailable("Ran out of rows to fetch at row=" +
  585.                                                 (lastRowRetrieved+1));
  586.                 } else {
  587.                     //inc last row and insert into map
  588.                     lastRowRetrieved = relView.getCurrentRecordNumber();
  589.                     lastIndex_++;
  590.                     growMap();
  591.                     rowMapping[lastIndex_] = lastRowRetrieved;
  592.                 }
  593.             }
  594.  
  595.             return rowMapping[r];
  596.         } catch (SQLException e) {
  597.             throw new DataNotAvailable(e.getMessage());
  598.         }
  599.     }
  600.  
  601.     //creates the new record and returns the translated row
  602.     //number
  603.     private int insertRowIntoMap(int r) throws DataNotAvailable {
  604.         int actual;
  605.  
  606.         try {
  607.             //make sure already mapped row
  608.             translateRow(r);
  609.  
  610.             //create a new record
  611.             relView.getNewRecord();
  612.             actual = relView.getCurrentRecordNumber();
  613.             createdRows.set(actual);
  614.  
  615.             //shift all array indices down one from specified row 'r'
  616.             growMap();
  617.             int numToCopy = lastIndex_+1-r;
  618.             System.arraycopy(rowMapping, r, rowMapping, r+1, numToCopy);
  619.             lastIndex_++;  //we just added a row but did not retrieve one
  620.             rowMapping[r] = actual;
  621.         } catch(Exception e) {
  622.             throw new DataNotAvailable(e.getMessage());
  623.         }
  624.  
  625.         return actual;
  626.     }
  627.  
  628.     //new row number of 1 relative
  629.     private int appendRowIntoMap() throws DataNotAvailable {
  630.         //record should NOT have already been created
  631.         //before call, lastRow will be the row number
  632.         //appended
  633.  
  634.         //move to end of all records
  635.         try {
  636.             while(!obtainedAllRows) {
  637.                 translateRow(lastRowRetrieved + 1);
  638.             }
  639.         } catch(DataNotAvailable ex) {
  640.             if (!obtainedAllRows) {
  641.                 throw ex;
  642.             }
  643.         }
  644.  
  645.         //create new record
  646.         try {
  647.             relView.getNewRecord();
  648.  
  649.             //get number and insert into map
  650.             growMap();
  651.             lastRowRetrieved = relView.getCurrentRecordNumber();
  652.             createdRows.set(lastRowRetrieved);
  653.             rowMapping[++lastIndex_] = lastRowRetrieved;
  654.         } catch(SQLException ex) {
  655.             throw new DataNotAvailable("Could not create new record");
  656.         }
  657.  
  658.         return lastIndex_;
  659.     }
  660.  
  661.     final void growMap() {
  662.         if (lastIndex_ == lastValidIndex-1) {  //minus 1 for safety b/c I'm tired
  663.             //grow array
  664.             int newMap[] = new int[lastValidIndex+=INC_SIZE];
  665.             System.arraycopy(rowMapping, 0, newMap, 0, rowMapping.length);
  666.             rowMapping = newMap;
  667.         }
  668.     }
  669.  
  670.     public Object getSynchronizationObject()
  671.     {
  672.         return multiView;
  673.     }
  674.  
  675. }
  676.  
  677. class Position
  678. {
  679.     int             frozenRecordNumber = 0;
  680.     int             notificationMode = 0;
  681.     boolean         frozen = false;
  682.     RelationView    relView;
  683.     int             ignoreCount = 0;
  684.     String          name = "";
  685.  
  686.     Position (RelationView rv)
  687.     {
  688.         relView = rv;
  689.         try
  690.         {
  691.             name = rv.getName();
  692.         }
  693.         catch (SQLException e)
  694.         {
  695.         }
  696.     }
  697.  
  698.     void freeze() throws SQLException
  699.     {
  700.         frozen = true;
  701.         ignoreNotification(true);
  702.         frozenRecordNumber = relView.getCurrentRecordNumber();
  703.         relView.enableBindingNotify(false, true);
  704.         relView.enableDetailSQL(false);
  705.     }
  706.  
  707.     void thaw() throws SQLException
  708.     {
  709.         if (frozenRecordNumber > 0)
  710.         {
  711.             goTo(frozenRecordNumber);
  712.         }
  713.         relView.enableDetailSQL(true);
  714.         relView.enableBindingNotify(true, true);
  715.         frozen = false;
  716.         ignoreNotification(false);
  717.     }
  718.  
  719.     boolean set(int recordNumber) throws SQLException
  720.     {
  721.         if (relView.getCurrentRecordNumber() == recordNumber)
  722.         {
  723.             return true;
  724.         }
  725.         if (getNotificationMode() && !frozen)
  726.         {
  727.             freeze();
  728.         }
  729.         return goTo(recordNumber);
  730.     }
  731.  
  732.     boolean goTo(int recordNumber) throws SQLException
  733.     {
  734.         boolean success = false;
  735.         ignoreNotification(true);
  736.         success = relView.goTo(recordNumber);
  737.         ignoreNotification(false);
  738.         return success;
  739.     }
  740.  
  741.     int get() throws SQLException
  742.     {
  743.         if (frozen)
  744.         {
  745.             return frozenRecordNumber;
  746.         }
  747.         return relView.getCurrentRecordNumber();
  748.     }
  749.  
  750.     void setNotificationMode(boolean mode) throws SQLException
  751.     {
  752.         if (mode)
  753.         {
  754.             notificationMode++;
  755.         }
  756.         else
  757.         {
  758.             notificationMode--;
  759.             if (notificationMode == 0 && frozen)
  760.             {
  761.                 thaw();
  762.             }
  763.         }
  764.     }
  765.  
  766.     boolean getNotificationMode()
  767.     {
  768.         return notificationMode > 0;
  769.     }
  770.  
  771.     void ignoreNotification(boolean flag)
  772.     {
  773.         if (flag)
  774.         {
  775.             ignoreCount++;
  776.         }
  777.         else
  778.         {
  779.             ignoreCount--;
  780.         }
  781.     }
  782.  
  783.     int getIgnoreCount()
  784.     {
  785.         return ignoreCount;
  786.     }
  787.  
  788. }